gdkkeys-win32: Fix crash when keyboard DLL failed to load
authorPhilip Zander <philip.zander@gmail.com>
Wed, 12 Jan 2022 20:31:21 +0000 (21:31 +0100)
committerLuca Bacci <luca.bacci982@gmail.com>
Wed, 12 Jan 2022 20:44:15 +0000 (21:44 +0100)
DLL loading failures should not happen under normal circumstances, but
we should at least try not to crash and and print better diagnostic
messages if they do happen.

See https://gitlab.gnome.org/GNOME/gtk/-/issues/4610

gdk/win32/gdkkeys-win32-impl.c
gdk/win32/gdkkeys-win32.c

index 4baf9201b362be624baf3295e7a01c267ec21ff4..b5640633b23d434216bec0b483e441dca5ac1616 100644 (file)
@@ -180,7 +180,8 @@ keystate_to_modbits (GdkWin32KeymapLayoutInfo *info,
   BYTE       result = 0;
   int        i;
 
-  g_return_val_if_fail (tables != NULL, 0);
+  if (tables == NULL)
+    return 0;
 
   vk_to_bit = tables->pCharModifiers.ptr->pVkToBit.ptr;
 
@@ -198,7 +199,8 @@ modbits_to_level (GdkWin32KeymapLayoutInfo *info,
   PKBDTABLES tables = (PKBDTABLES) info->tables;
   PMODIFIERS modifiers;
 
-  g_return_val_if_fail (tables != NULL, 0);
+  if (tables == NULL)
+    return 0;
 
   modifiers = tables->pCharModifiers.ptr;
   if (modbits > modifiers->wMaxModBits)
@@ -268,7 +270,8 @@ vk_to_char_fuzzy (GdkWin32KeymapLayoutInfo *info,
   if (is_dead)
     *is_dead = FALSE;
 
-  g_return_val_if_fail (tables != NULL, WCH_NONE);
+  if (tables == NULL)
+    return WCH_NONE;
 
   wch_tables = tables->pVkToWcharTable.ptr;
 
index 43de7eb7d6b588f07e9183c2e6c541996b2f005d..f41f26799755a167b3267229ad48eba6c96d8110 100644 (file)
@@ -181,6 +181,7 @@ get_keyboard_layout_file (const char *layout_name)
   DWORD  file_name_len = 0;
   int    dir_len       = 0;
   int    buf_len       = 0;
+  LSTATUS status;
 
   static const char prefix[] = "SYSTEM\\CurrentControlSet\\Control\\"
                                "Keyboard Layouts\\";
@@ -189,18 +190,32 @@ get_keyboard_layout_file (const char *layout_name)
   g_snprintf (kbdKeyPath, sizeof (prefix) + KL_NAMELENGTH, "%s%s", prefix,
               layout_name);
 
-  if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, (LPCSTR) kbdKeyPath, 0,
-                     KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
-    goto fail1;
+
+  status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, (LPCSTR) kbdKeyPath, 0,
+                          KEY_QUERY_VALUE, &hkey);
+  if (status != ERROR_SUCCESS)
+    {
+      g_warning("Could not open registry key '%s'. Error code: %d",
+                kbdKeyPath, (int)status);
+      goto fail1;
+    }
 
   /* Get sizes */
-  if (RegQueryValueExA (hkey, "Layout File", 0, &var_type, 0,
-                       &file_name_len) != ERROR_SUCCESS)
-    goto fail2;
+  status = RegQueryValueExA (hkey, "Layout File", 0, &var_type, 0,
+                             &file_name_len);
+  if (status != ERROR_SUCCESS)
+    {
+      g_warning("Could not query registry key '%s\\Layout File'. Error code: %d",
+                kbdKeyPath, (int)status);
+      goto fail2;
+    }
 
   dir_len = GetSystemDirectoryA (0, 0); /* includes \0 */
   if (dir_len == 0)
-    goto fail2;
+    {
+      g_warning("GetSystemDirectoryA failed. Error: %d", (int)GetLastError());
+      goto fail2;
+    }
 
   /* Allocate buffer */
   buf_len = dir_len + (int) strlen ("\\") + file_name_len;
@@ -214,10 +229,12 @@ get_keyboard_layout_file (const char *layout_name)
   result[dir_len - 1] = '\\';
 
   /* Append file name */
-  if (RegQueryValueExA (hkey, "Layout File", 0, &var_type,
-                       (LPBYTE) &result[dir_len], &file_name_len)
-      != ERROR_SUCCESS)
-    goto fail3;
+  status = RegQueryValueExA (hkey, "Layout File", 0, &var_type,
+                             (LPBYTE) &result[dir_len], &file_name_len);
+  if (status != ERROR_SUCCESS)
+    {
+      goto fail3;
+    }
 
   result[dir_len + file_name_len] = '\0';
 
@@ -415,6 +432,9 @@ gdk_keysym_to_key_entry_index (GdkWin32KeymapLayoutInfo *info,
   gunichar c;
   gintptr  index;
 
+  if (info->reverse_lookup_table == NULL)
+    return -1;
+
   /* Special cases */
   if (sym == GDK_KEY_Tab)
     return VK_TAB;
@@ -439,8 +459,6 @@ gdk_keysym_to_key_entry_index (GdkWin32KeymapLayoutInfo *info,
   /* Try converting to Unicode and back */
   c = gdk_keyval_to_unicode (sym);
 
-  g_return_val_if_fail (info->reverse_lookup_table != NULL, -1);
-
   index = -1;
   if (g_hash_table_lookup_extended (info->reverse_lookup_table,
                                     GINT_TO_POINTER (c),
@@ -537,7 +555,7 @@ update_keymap (GdkWin32Keymap *keymap)
 
           info->file = get_keyboard_layout_file (info->name);
 
-          if (load_layout_dll (keymap, info->file, info))
+          if (info->file != NULL && load_layout_dll (keymap, info->file, info))
             {
               info->key_entries = g_array_new (FALSE, FALSE,
                                                sizeof (GdkWin32KeymapKeyEntry));
@@ -546,6 +564,11 @@ update_keymap (GdkWin32Keymap *keymap)
                                                              g_direct_equal);
               init_vk_lookup_table (keymap, info);
             }
+          else
+            {
+              g_warning("Failed to load keyboard layout DLL for layout %s: %s",
+                        info->name, info->file);
+            }
         }
 
       if (info->handle == current_layout)
@@ -978,6 +1001,13 @@ gdk_win32_keymap_translate_keyboard_state (GdkKeymap       *gdk_keymap,
   if (consumed_modifiers)
     *consumed_modifiers = mod_bits_to_gdk_mod_mask (consumed_mod_bits);
 
+  /* Just a diagnostic message to inform the user why their keypresses aren't working.
+   * Shouldn't happen under normal circumstances. */
+  if (tmp_keyval == GDK_KEY_VoidSymbol && layout_info->tables == NULL)
+    g_warning("Failed to translate keypress (keycode: %u) for group %d (%s) because "
+              "we could not load the layout.",
+              hardware_keycode, group, layout_info->name);
+
   return tmp_keyval != GDK_KEY_VoidSymbol;
 }